package juc2.threadpool;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * ThreadPoolExecutor使用示例 - 模拟订单处理系统
 * 这个示例展示了线程池的完整生命周期：创建配置 -> 提交任务 -> 处理结果 -> 监控状态 -> 优雅关闭
 */
public class OrderThreadPoolExample {

    /**
     * 自定义线程工厂
     * 作用：创建线程时可以自定义线程名称、优先级、异常处理器等，便于问题排查和线程管理
     */
    static class OrderThreadFactory implements ThreadFactory {
        // 线程池编号，用于区分多个线程池
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        // 线程组，用于管理一组线程
        private final ThreadGroup group;
        // 线程编号，用于区分同一线程池中的不同线程
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        // 线程名称前缀
        private final String namePrefix;

        public OrderThreadFactory() {
            // 获取安全管理器，用于获取线程组
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
            // 生成线程名称前缀，包含池编号，例如"order-pool-1-thread-"
            namePrefix = "order-pool-" + poolNumber.getAndIncrement() + "-thread-";
        }

        /**
         * 创建新线程
         * @param r 线程要执行的任务
         * @return 新创建的线程
         */
        @Override
        public Thread newThread(Runnable r) {
            // 创建线程，设置线程组、任务、名称和栈大小
            Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);

            // 设置为非守护线程：
            // 守护线程会在主线程结束时自动退出，而非守护线程则会继续执行
            // 对于线程池，通常使用非守护线程以确保任务能完成
            if (t.isDaemon()) {
                t.setDaemon(false);
            }

            // 设置线程优先级为正常：
            // 优先级范围1-10，默认为5(NORM_PRIORITY)
            // 除非有特殊需求，一般不修改优先级，避免线程饥饿
            if (t.getPriority() != Thread.NORM_PRIORITY) {
                t.setPriority(Thread.NORM_PRIORITY);
            }

            // 设置未捕获异常处理器：
            // 处理线程中未捕获的异常，避免异常静默丢失
            t.setUncaughtExceptionHandler((thread, throwable) ->
                    System.err.println("线程" + thread.getName() + "发生未捕获异常: " + throwable.getMessage()));

            return t;
        }
    }

    /**
     * 订单处理任务
     * 实现Callable接口，支持返回结果和抛出异常
     */
    static class OrderTask implements Callable<String> {
        private final int orderId;  // 订单ID
        private final Random random = new Random();  // 随机数生成器，用于模拟处理时间和失败情况

        public OrderTask(int orderId) {
            this.orderId = orderId;
        }

        /**
         * 任务执行方法
         * @return 处理结果
         * @throws Exception 处理过程中可能抛出的异常
         */
        @Override
        public String call() throws Exception {
            // 记录当前处理线程名称，用于观察线程复用情况
            String threadName = Thread.currentThread().getName();

            // 模拟订单处理耗时（1-3秒）
            // 实际场景中可能是数据库操作、RPC调用等IO密集型任务
            long handleTime = random.nextInt(3) + 1;
            System.out.println(threadName + " 开始处理订单" + orderId + "，预计耗时" + handleTime + "秒");
            Thread.sleep(handleTime * 1000);  // 模拟处理过程

            // 模拟部分任务处理失败（每7个订单失败一次）
            if (orderId % 7 == 0) {
                throw new RuntimeException("订单" + orderId + "处理失败（库存不足）");
            }

            return threadName + "：订单" + orderId + "处理完成（耗时" + handleTime + "秒）";
        }
    }

    public static void main(String[] args) {
        // 1. 创建线程池（核心参数根据业务场景配置）
        // 线程池的创建是核心，参数设置直接影响性能和稳定性
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                5,                  // 核心线程数：5个常驻线程
                // 核心线程会一直保持，即使空闲（除非设置allowCoreThreadTimeOut为true）
                // 这里设置5是因为根据业务评估，系统平时稳定有5个并发订单处理

                10,                 // 最大线程数：最多10个线程
                // 当核心线程都在忙且队列满时，会创建非核心线程，最多到10个
                // 设置10是考虑到业务高峰期可能出现的并发峰值

                60,                 // 非核心线程空闲60秒后销毁
                // 非核心线程是临时的，空闲时销毁以节省资源

                TimeUnit.SECONDS,   // 时间单位：秒

                new ArrayBlockingQueue<>(20), // 任务队列：有界队列，容量20
                // 使用有界队列防止任务无限堆积导致OOM
                // 容量20是根据系统能承受的最大等待任务数设置的

                new OrderThreadFactory(),     // 线程工厂：自定义线程名
                // 便于日志追踪和问题排查

                new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略：提交任务的线程执行
                // 当线程池和队列都满时，让提交任务的主线程执行任务
                // 这样会降低提交速度，起到自我保护作用
        );

        // 2. 提交一批订单处理任务（30个任务）
        // 使用List保存Future对象，用于后续获取任务结果
        List<Future<String>> futures = new ArrayList<>();
        for (int i = 1; i <= 30; i++) {
            OrderTask task = new OrderTask(i);
            // 提交任务并获取Future对象（用于获取结果）
            // submit()与execute()的区别：
            // - submit()可以提交Callable任务，支持返回结果
            // - submit()会捕获任务中的异常，通过Future.get()获取
            Future<String> future = threadPool.submit(task);
            futures.add(future);

            // 提交5个任务后打印一次线程池状态，观察线程池变化
            if (i % 5 == 0) {
                printThreadPoolStatus(threadPool, "提交第" + i + "个任务后");
            }
        }

        // 3. 获取任务执行结果
        System.out.println("\n===== 开始获取任务结果 =====");
        for (Future<String> future : futures) {
            try {
                // 获取结果（会阻塞直到任务完成）
                // 也可以使用future.get(timeout, unit)设置超时时间，避免无限等待
                String result = future.get();
                System.out.println("结果：" + result);
            } catch (InterruptedException e) {
                // 处理中断异常：当获取结果的线程被中断时抛出
                System.err.println("获取结果被中断：" + e.getMessage());
                Thread.currentThread().interrupt(); // 恢复中断状态，让上层感知
            } catch (ExecutionException e) {
                // 处理任务执行异常：任务中抛出的异常会被封装在ExecutionException中
                System.err.println("任务执行异常：" + e.getCause().getMessage());
            }
        }

        // 4. 优雅关闭线程池
        // 线程池使用完毕后必须关闭，否则会导致线程泄露
        System.out.println("\n===== 开始关闭线程池 =====");
        threadPool.shutdown(); // 平缓关闭：不再接受新任务，但会处理完队列中现有任务

        try {
            // 等待60秒让线程池完成关闭
            // awaitTermination返回true表示线程池已完全关闭，false表示超时
            if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) {
                // 超时后强制关闭：尝试中断所有正在执行的任务，并返回未执行的任务
                threadPool.shutdownNow();

                // 再次等待强制关闭完成
                if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) {
                    System.err.println("线程池未能完全关闭");
                }
            }
        } catch (InterruptedException e) {
            // 等待过程中被中断，强制关闭线程池
            threadPool.shutdownNow();
            Thread.currentThread().interrupt(); // 恢复中断状态
        }

        System.out.println("线程池已关闭，状态：" + (threadPool.isTerminated() ? "已终止" : "未终止"));
    }

    /**
     * 打印线程池当前状态（监控用）
     * 监控线程池状态有助于理解线程池工作情况和排查问题
     */
    private static void printThreadPoolStatus(ThreadPoolExecutor threadPool, String label) {
        System.out.println("\n===== " + label + " 线程池状态 =====");
        System.out.println("核心线程数：" + threadPool.getCorePoolSize());
        System.out.println("当前活跃线程数：" + threadPool.getActiveCount() + "（正在执行任务的线程）");
        System.out.println("最大线程数：" + threadPool.getMaximumPoolSize());
        System.out.println("总任务数：" + threadPool.getTaskCount() + "（已提交的所有任务）");
        System.out.println("已完成任务数：" + threadPool.getCompletedTaskCount());
        System.out.println("队列当前任务数：" + threadPool.getQueue().size());
        System.out.println("队列剩余容量：" + threadPool.getQueue().remainingCapacity());
        System.out.println("线程池状态：" + getPoolStatus(threadPool));
    }

    /**
     * 获取线程池状态描述
     * 线程池有5种状态：RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED
     */
    private static String getPoolStatus(ThreadPoolExecutor threadPool) {
        if (threadPool.isTerminated()) {
            return "TERMINATED（已终止：所有任务完成，线程已销毁）";
        } else if (threadPool.isTerminating()) {
            return "TIDYING/TERMINATING（正在终止：任务处理中，即将完成）";
        } else if (threadPool.isShutdown()) {
            return "SHUTDOWN（已关闭：不再接受新任务，但处理已有任务）";
        } else {
            return "RUNNING（运行中：正常接受和处理任务）";
        }
    }
}


